package org.windowkit.toolkit.widget.treetable.ui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;

import javax.swing.JComponent;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicTableUI;
import javax.swing.tree.TreePath;

import org.windowkit.toolkit.widget.treetable.TreeTableModel;
import org.windowkit.toolkit.widget.treetable.DefaultTreeTableModel.DSTreeNode;


/**
 * Since we put our nodes into different table columns we have to draw our own
 * lines. This is easier than translating from tree coordinates to table
 * coordinates to cell renderer coordinates whenever the super ui is going to
 * draw.
 *
 * @author Eric Lundin
 */
public class TreeTableUI extends BasicTableUI {
	JTree tree;

	BasicStroke dashedStroke = new BasicStroke(1, 2, 0, 10,
			new float[] { 1, 3 }, 0);

	Color lineColor = UIManager.getColor("Tree.line");

	private final int closedIconWidth = UIManager.getIcon("Tree.closedIcon")
			.getIconWidth();

	private final int openIconWidth = UIManager.getIcon("Tree.openIcon")
			.getIconWidth();

	private final int leafIconWidth = UIManager.getIcon("Tree.leafIcon")
			.getIconWidth();

	public TreeTableUI(final JTree theTree) {
		tree = theTree;
	}

	@Override
	public void paint(final Graphics g, final JComponent c) {

		for (int i = 1; i < tree.getRowCount(); i++) {
			for (int j = 1; j <= table.getColumnCount(); j++) {
				DSTreeNode node = (DSTreeNode) nodeForRow(i);
				int parentRow = findParentRow(i);
				DSTreeNode parentNode = (DSTreeNode) nodeForRow(parentRow);
				if (getTreeModel().getDataLevel(node) == j) {
					g.setColor(Color.black);
					drawLine(parentRow, i, getTreeModel().getDataLevel(
							parentNode), getTreeModel().getDataLevel(node), g);
				}
			}
		}
		super.paint(g, c);
	}

	private TreeTableModel getTreeModel() {
		return (TreeTableModel) tree.getModel();
	}

	public int getIconWidth(final int row) {
		return tree.getModel().isLeaf(nodeForRow(row)) ? leafIconWidth : tree
				.isExpanded(row) ? openIconWidth : closedIconWidth;
	}

	private void drawLine(final int parentRow, final int childRow, final int parentLevel,
			final int childLevel, final Graphics g) {
		int childX = getColumnOffSet(childLevel);
		int parentX = getColumnOffSet(parentLevel)
				+ (getIconWidth(parentRow) / 2);
		int childY = (childRow * (table.getRowHeight() + table
				.getIntercellSpacing().height))
				+ ((table.getRowHeight() + table.getIntercellSpacing().height) / 2);
		int parentY = (parentRow * (table.getRowHeight() + table
				.getIntercellSpacing().height))
				+ ((table.getRowHeight() + table.getIntercellSpacing().height));
		if (UIManager.getBoolean("Tree.lineTypeDashed")) {
			Stroke current = ((Graphics2D) g).getStroke();
			((Graphics2D) g).setStroke(dashedStroke);
			// Draw dashed lines as 0 area rectangles because Java can only
			// stroke dashed shapes for some reason.
			g.drawRect(parentX, childY, childX - parentX, 0);
			g.drawRect(parentX, parentY, 0, childY - parentY);
			((Graphics2D) g).setStroke(current);
		} else {
			g.drawLine(childX, childY, parentX, childY);
			g.drawLine(parentX, childY, parentX, parentY);
		}
	}

	private int findParentRow(final int childRow) {
		int row = 0;
		for (int i = childRow - 1; i >= 0; i--) {
			// if (tree.getModel().getIndexOfChild(nodeForRow(i),
			// nodeForRow(childRow)) != -1) {
			// row = i;
			// break;
			// }
			if (getTreeModel().getLevel(nodeForRow(i)) < getTreeModel()
					.getLevel(nodeForRow(childRow))) {
				return i;
			}
		}

		return row;
	}

	private int getColumnOffSet(final int column) {
		int offset = 0;
		for (int i = 0; i < column; i++) {
			offset += table.getColumnModel().getColumn(i).getWidth();
		}
		return offset;
	}

	protected Object nodeForRow(final int row) {
		TreePath treePath = tree.getPathForRow(row);
		return treePath.getLastPathComponent();
	}

}
